﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

using Boggle;

using NUnit.Framework;

namespace Boggle.Tests
{
    class TestDie
	{
		#region Ctor

		[Test, TestCaseSource("GetCtorCases")]
        public void TestCtor(String[] faces, String expectedCurrentValue)
        {
            var d = new Die(faces);
            Assert.AreEqual(expectedCurrentValue, d.CurrentValue);
        }

        private IEnumerable<ITestCaseData> GetCtorCases()
        {
            yield return new TestCaseData(null, null)
                .Throws<ArgumentNullException>();

            yield return new TestCaseData(new String[] { }, null)
                .Throws<ArgumentException>();

            yield return new TestCaseData(new String[] { null }, null)
                .Throws<ArgumentException>();

            yield return new TestCaseData(new String[] { "a", "b", "c", null, "e", "f" }, null)
                .Throws<ArgumentException>();

            yield return new TestCaseData(new String[] { null }, null)
                .Throws<ArgumentException>();

            yield return new TestCaseData(new String[] { "a" }, "a");

            yield return new TestCaseData(new String[] { "a", "b", "c", "d", "", "f" }, null)
                .Throws<ArgumentException>();

            yield return new TestCaseData(new String[] { "a", "b", "c", "d", "e", "f" }, "a");

            yield return new TestCaseData(new String[] { "alex", "barney", "charles", "dianne", "edwina", "frances" }, "alex");
        }

		#endregion

		#region ToString

		[Test, TestCaseSource("GetToStringCases")]
        public String TestToString(Die die)
        {
            return die.ToString();
        }

        private IEnumerable<ITestCaseData> GetToStringCases()
        {
            yield return new TestCaseData(
                new Die(new String[] { "a" }))
                .Returns("(a) - [a]");

            yield return new TestCaseData(
                new Die(new String[] { "a", "b", "c", "d", "e", "f" }))
                .Returns("(a) - [a,b,c,d,e,f]");

            yield return new TestCaseData(
                new Die(new String[] { "a", "b", "c", "d", "e", "f", "qu" }))
                .Returns("(a) - [a,b,c,d,e,f,qu]");
		}

		#endregion

		#region Roll

		/// <summary>
		/// Tests the Roll method for fairness.
		/// This test won't fail, but may be marked inconclusive.
		/// </summary>
		[Test]
		public void TestRoll()
		{
			var faces = new String[] { "a", "b", "c", "d", "e", "f" };
			var die = new Die(faces);
			var frequency = new Dictionary<String, Int32>(6);
			
			foreach (var face in faces)
			{
				frequency.Add(face, 0);
			}
			
			var rolls = 1000000;
			var upperAllowedBound = (rolls / 6) * 1.1;
			var lowerAllowedBound = (rolls / 6) * 0.9;

			for (var i = 0; i < rolls; i++)
			{
				die.Roll();
				frequency[die.CurrentValue]++;
			}

			foreach (var result in frequency)
			{
				Trace.WriteLine(String.Format("{0} rolled {1} times", result.Key, result.Value));
			}

			if (frequency.Select(f => f.Value).Any(v => v > upperAllowedBound || v < lowerAllowedBound))
			{
				Assert.Inconclusive("The die rolls do not appear to be fair");
			}
		}

		#endregion
	}
}
